package com.lsh.ofc.core.handler;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.lsh.base.common.exception.BusinessException;
import com.lsh.ofc.core.base.AbstractTask;
import com.lsh.ofc.core.constant.Constants;
import com.lsh.ofc.core.dao.OfcSoDetailDAO;
import com.lsh.ofc.core.entity.*;
import com.lsh.ofc.core.enums.*;
import com.lsh.ofc.core.exception.EC;
import com.lsh.ofc.core.mail.EmailHandler;
import com.lsh.ofc.core.service.OfcSoCreateService;
import com.lsh.ofc.core.service.OfcSoService;
import com.lsh.ofc.proxy.context.WumartBasicContext;
import com.lsh.ofc.proxy.model.*;
import com.lsh.ofc.proxy.model.MeipiCustomer;
import com.lsh.ofc.proxy.service.AtpServiceProxy;
import org.apache.log4j.Logger;
import org.springframework.context.ApplicationContext;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * 创建SO处理Handler
 *
 * @author huangdong
 * @date 16/9/9
 */
public abstract class CreateSoHandler extends AbstractTask<Boolean> {

    protected final Logger logger = Logger.getLogger(this.getClass());
    protected final OfcSoService ofcSoService;
    protected final OfcSoCreateService ofcSoCreateService;
    private final OfcSoDetailDAO ofcSoDetailDAO;
    private final OfcOrderHead ofcOrderHead;
    private final OfcSoHead so;
    private final OfcCustomer customer;
    private final EmailHandler emailHandler;
    private final AtpServiceProxy atpServiceProxy;

    protected CreateSoHandler(final ApplicationContext context, final OfcOrderHead ofcOrderHead, final OfcSoHead so, final OfcCustomer customer) {
        Assert.notNull(context, "context can not be null!");
        Assert.notNull(ofcOrderHead, "order can not be bull!");
        Assert.notNull(so, "so can not be null!");
        Assert.notNull(customer, "customer can not be null!");
        this.ofcOrderHead = ofcOrderHead;
        this.so = so;
        this.customer = customer;
        this.ofcSoDetailDAO = context.getBean(OfcSoDetailDAO.class);
        this.ofcSoService = context.getBean(OfcSoService.class);
        this.ofcSoCreateService = context.getBean(OfcSoCreateService.class);
        this.emailHandler = context.getBean(EmailHandler.class);
        this.atpServiceProxy = context.getBean(AtpServiceProxy.class);
    }

    /**
     * @param context
     * @param ofcOrderHead
     * @param so
     * @param customer
     * @return
     * @throws BusinessException
     */
    public static CreateSoHandler newInstance(final ApplicationContext context, final OfcOrderHead ofcOrderHead, final OfcSoHead so, final OfcCustomer customer) throws BusinessException {
        Assert.notNull(context, "context can not be null!");
        Assert.notNull(ofcOrderHead, "order can not be null!");
        Assert.notNull(so, "so can not be null!");
        Assert.notNull(customer, "customer can not be null!");
        FulfillChannel channel = FulfillChannel.valueOf(so.getFulfillChannel());
        if (channel == null) {
            throw EC.ERROR.exception("fulfill channel is not support!!! channel=" + so.getFulfillChannel());
        }

        try {
            return channel.getCreateSoHandlerType().getDeclaredConstructor(ApplicationContext.class, OfcOrderHead.class, OfcSoHead.class, OfcCustomer.class).newInstance(context, ofcOrderHead, so, customer);
        } catch (Exception e) {
            throw EC.ERROR.exception(e);
        }
    }

    @Override
    public Boolean execute() throws BusinessException {

        if (!SoStatus.UNCREATED.getValue().equals(so.getSoStatus())) {
            logger.warn("SO状态不是\"待创建\"！SO单号=" + so.getSoCode() + "，状态=" + so.getSoStatus());
            return true;
        }
        if (CollectionUtils.isEmpty(this.so.getDetails())) {
            OfcSoDetail params = new OfcSoDetail();
            params.setSoBillCode(this.so.getSoBillCode());
            this.so.setDetails(this.ofcSoDetailDAO.findList(params));
        }
        try {
            return this.process(this.so, this.customer);
        } catch (Throwable e) {
            logger.error("【" + this.so.getSoBillCode() + "】创建SO异常" + e.getMessage(), e);
            this.sendMail(this.so.getSoBillCode(), e.getMessage(), EmailHandler.EmailTopic.SO_CREATE_PRECESS);
            return false;
        }
    }

    protected abstract boolean process(final OfcSoHead so, final OfcCustomer customer) throws BusinessException;

    /**
     * 发送邮件
     *
     * @param orderCode
     * @param message
     * @param topic
     */
    private void sendMail(String orderCode, String message, EmailHandler.EmailTopic topic) {
        try {
            StringBuilder builder = new StringBuilder();
            if (org.apache.commons.lang3.StringUtils.isNotBlank(message) && message.length() > 200) {
                message = message.substring(0, 200);
            }
            builder.append("so_bill_code ：").append(orderCode).append("\n");
            builder.append("错误信息：").append(message).append("\n");
            this.emailHandler.buildEmail(topic, builder.toString());
        } catch (Exception e) {
            logger.error("so push 异常邮件发送失败:" + e.getMessage(), e);
        }
    }

    /**
     * 链商wms 请求参数
     *
     * @return
     */
    protected CreateLshSoReqHead getCreateLshSoReq() {
        Integer tmpTransTime = JSONObject.parseObject(this.so.getExt()).getInteger(Constants.SO_H_TRANS_TIME);
        Date transTime = new Date(tmpTransTime * 1000L);

        CreateLshSoReqHead order = new CreateLshSoReqHead();
        order.setWarehouseCode(this.so.getSupplierDc());
        order.setOrderOtherId(this.so.getSoBillCode());
        order.setOrderOtherRefId("");
        order.setOrderUserCode("");
        order.setOrderUser("");
        order.setDeliveryName(this.customer.getCustName());
        order.setDeliveryCode(this.customer.getMpCustCode());
        order.setTelephone(this.customer.getContactPhone());
        Integer ownerUid = this.so.getSupplierOrg();
        //TODO wms 货主
        if (ownerUid == 3) {
            ownerUid = 2;
        }
        order.setOwnerUid(Long.valueOf(ownerUid));
        order.setOrderType(WMSOrderType.So.getCode());
        order.setTransTime(transTime);
        order.setShipperProvince(this.customer.getProvince());
        order.setShipperCity(this.customer.getCity());
        order.setShipperDistrict(this.customer.getDistrict());
        order.setDeliveryAddrs(this.customer.getAddress());
        order.setSourceSystem("2");

        //wms下发超市坐标及具体地址信息
        JSONObject ext = new JSONObject();
        ext.put("position", this.customer.getLocation());
        ext.put("address", JSONObject.parseObject(this.ofcOrderHead.getAddressInfo()).getString("address"));
        order.setExt(ext.toJSONString());

        order.setAddressInfo(this.ofcOrderHead.getAddressInfo());

        List<OfcSoDetail> soDetails = this.so.getDetails();
        List<CreateLshSoReqDetail> details = new ArrayList<>(soDetails.size());
        for (OfcSoDetail soDetail : soDetails) {

            String detailExt = soDetail.getExt();
            Integer skuDefine = SkuDefine.EA.getCode();
            if (!StringUtils.isEmpty(detailExt)) {
                JSONObject soext = JSON.parseObject(detailExt);
                skuDefine = soext.getInteger(Constants.ORDER_D_SKU_DEFINE);
            }

            if (skuDefine == null) {
                skuDefine = SkuDefine.EA.getCode();
            }

            CreateLshSoReqDetail detail = new CreateLshSoReqDetail();
            detail.setDetailOtherId(soDetail.getItemNo());
            detail.setSkuCode(soDetail.getSkuSupplyCode());

            if (skuDefine.equals(SkuDefine.KG.getCode())) {
                detail.setUnitName(SkuDefine.KG.getDesc());
                detail.setPackName(SkuDefine.KG.getDesc());
            } else {
                detail.setUnitName(SkuDefine.EA.getDesc());
                detail.setPackName(SkuDefine.EA.getDesc());
            }
            //TODO:箱规,默认写1
            detail.setPackUnit(1);
            detail.setOrderQty(soDetail.getSkuOrderQty());
            //国条码
            detail.setBarCode("");
            //批号
            detail.setLotNum("");
            detail.setPrice(soDetail.getGoodsPrice().divide(soDetail.getGoodsSaleUnit(), 2, BigDecimal.ROUND_HALF_UP));
            detail.setUnitQty(soDetail.getSkuOrderQty());
            details.add(detail);
        }

        order.setDetailList(details);
        return order;
    }

    /**
     * 请求分拣中心 下发so 请求参数
     *
     * @return
     */
    protected CreateScSoReqHead getCreateScSoReq() {
        CreateScSoReqHead scSoReqHead = new CreateScSoReqHead();
        scSoReqHead.setWarehouseCode(this.so.getSupplierDc());
        scSoReqHead.setOrderOtherId(this.so.getSoBillCode());
        scSoReqHead.setOrderOtherRefId(String.valueOf(this.so.getOrderCode()));
        scSoReqHead.setDeliveryName(this.customer.getCustName());
        scSoReqHead.setDeliveryCode(this.customer.getMpCustCode());
        Integer ownerUid = this.so.getSupplierOrg();

        scSoReqHead.setOwnerId(Long.valueOf(ownerUid));
        if (so.getFulfillChannel().equals(FulfillChannel.SAAS_SC.getValue())) {
            // todo：云仓订单
            scSoReqHead.setOrderType(4);
        } else {
            scSoReqHead.setOrderType(1);
        }
        // todo：系统来源
        scSoReqHead.setSourceSystem("2");

        JSONObject ext = JSON.parseObject(so.getExt());
        if (ext != null && ext.size() > 0) {
            String providerName = ext.getString("provider_name");
            // 供商名称
            scSoReqHead.setSupplierName(providerName);
        }
        // 供商码
        scSoReqHead.setSupplierCode(String.valueOf(this.so.getSupplierId()));

        List<OfcSoDetail> soDetails = this.so.getDetails();
        List<CreateScSoReqDetail> details = new ArrayList<>(soDetails.size());
        for (OfcSoDetail soDetail : soDetails) {
            String detailExt = soDetail.getExt();
            Integer skuDefine = SkuDefine.EA.getCode();
            String barCode = "";
            logger.info("detailExt is " + detailExt);
            if (!StringUtils.isEmpty(detailExt)) {
                JSONObject soExt = JSON.parseObject(detailExt);
                skuDefine = soExt.getInteger(Constants.ORDER_D_SKU_DEFINE);
                barCode = soExt.getString(Constants.ORDER_ITEM_BARCODE);
            }

            if (skuDefine == null) {
                skuDefine = SkuDefine.EA.getCode();
            }

            if (StringUtils.isEmpty(barCode)) {

            }

            CreateScSoReqDetail detail = new CreateScSoReqDetail();
            detail.setDetailOtherId(soDetail.getItemCode());
            detail.setSkuCode(soDetail.getSkuSupplyCode());

            if (skuDefine.equals(SkuDefine.KG.getCode())) {
                detail.setUnitName(SkuDefine.KG.getDesc());
                detail.setPackName(SkuDefine.KG.getDesc());
            } else {
                detail.setUnitName(SkuDefine.EA.getDesc());
                detail.setPackName(SkuDefine.EA.getDesc());
            }

            //TODO:箱规,默认写1
            detail.setPackUnit(1);
            detail.setCode(barCode);
            detail.setSkuName(soDetail.getGoodsName());
            detail.setOrderQty(soDetail.getSkuOrderQty());
            detail.setUnitQty(soDetail.getSkuOrderQty());
            details.add(detail);
        }

        scSoReqHead.setDetails(details);
        return scSoReqHead;
    }

    /**
     * 进销存 请求参数
     *
     * @param costomerId
     * @param ownerId
     * @return
     */
    protected CreateWgSoReqHead getCreateWgSoReq(String costomerId, String ownerId) {
        Integer tmpTransTime = JSONObject.parseObject(this.so.getExt()).getInteger(Constants.SO_H_TRANS_TIME);
        Date transTime = new Date(tmpTransTime * 1000L);

        CreateWgSoReqHead order = new CreateWgSoReqHead();
        order.setCustomerId(costomerId);
        order.setOwnerId(ownerId);
        order.setMisVenderId(this.so.getVenderId());
        order.setWarehouseCode(this.so.getSupplierDc());

        JSONObject soHeadExt = JSON.parseObject(this.so.getExt());
        Integer preSale = soHeadExt.getInteger(WumartBasicContext.SO_ORDER_TYPE);

        String providerId = soHeadExt.getString("provider_id");
        Integer saleModel = soHeadExt.getInteger("saleModel");
        Integer deliveryType = soHeadExt.getInteger("deliveryType");

        if (preSale.equals(SoOrderType.PRE_SALE.getValue())) {
            order.setOrderType(String.valueOf(WGOrderType.PRESEll_SO.getCode()));
        } else {
            order.setOrderType(String.valueOf(WGOrderType.SO.getCode()));
        }

        order.setTransTime(String.valueOf(transTime.getTime()));
        order.setOrderOtherRefId(this.so.getOrderCode() + "");
        order.setOrderId(this.so.getSoBillCode());
        JSONObject ext = new JSONObject();
        ext.put("position", this.customer.getLocation());
        ext.put("address", JSONObject.parseObject(this.ofcOrderHead.getAddressInfo()).getString("address"));
        ext.put("providerId", providerId);
        ext.put("saleModel", saleModel);
        ext.put("deliveryType", deliveryType);
        ext.put("orderTime",this.so.getOrderTime());

        order.setExt(ext.toJSONString());
        order.setAddressInfo(this.ofcOrderHead.getAddressInfo());
        order.setOrderCustomerName(this.customer.getCustName());

        JSONObject address = JSON.parseObject(this.ofcOrderHead.getAddressInfo());
        String duoDianOrder = address.getString("DuoDianOrder");
        if (!StringUtils.isEmpty(duoDianOrder)) {
            String dMallParentOrderId = address.getString("dMallParentOrderId");
            if(StringUtils.isEmpty(dMallParentOrderId)){
                dMallParentOrderId = address.getString("DuoDianOrderId");
            }
            order.setOrderCustomerId(dMallParentOrderId);
        }else {
            order.setOrderCustomerId(String.valueOf(this.customer.getMpCustCode()));
        }
//        order.setOrderCustomerId(String.valueOf(this.customer.getMpCustCode()));

        List<OfcSoDetail> soDetails = this.so.getDetails();
        List<CreateWgSoReqDetail> details = new ArrayList<>(soDetails.size());

        //先遍历一遍，取商品信息
        List<Long> itemIds = new ArrayList<>();
        for (OfcSoDetail soDetail : soDetails) {
            itemIds.add(soDetail.getSkuCode());
        }
        Map<Long, Integer> preSaleItemMap = atpServiceProxy.querySkuPreSale(so.getRegionCode().toString(), so.getVenderId(), so.getSupplierOrg(), so.getSupplierId(), so.getSupplierCode(), itemIds);

        for (OfcSoDetail soDetail : soDetails) {

            CreateWgSoReqDetail detail = new CreateWgSoReqDetail();
            if (soDetail.getItemCode() == 0) {
                detail.setLineNo(String.valueOf(soDetail.getItemNo()));
            } else {
                detail.setLineNo(String.valueOf(soDetail.getItemCode()));
            }

            if (preSaleItemMap.containsKey(soDetail.getSkuCode())) {
                detail.setPreSale(1);
            } else {
                detail.setPreSale(0);
            }

            detail.setGoodsId(soDetail.getSkuSupplyCode());

            //TODO:箱规,默认写1
            detail.setUnit("1");
            detail.setQty(soDetail.getSkuOrderQty());
            //TODO 默认1
            detail.setOwnerId(ownerId);

            JSONObject detailExt = JSON.parseObject(soDetail.getExt());
            Integer weighingFlag = detailExt.getInteger(Constants.ORDER_ITEM_WEIGHT_FLAG);
            if (null == weighingFlag) {
                weighingFlag = 0;
            }

            detail.setIsWeighingGoods(weighingFlag);
            //TODO 下发进销存
            BigDecimal saleUnit = soDetail.getGoodsSaleUnit();
            BigDecimal goodsPrice = soDetail.getGoodsPrice();
            if (saleUnit.compareTo(BigDecimal.ZERO) > 0 && goodsPrice.compareTo(BigDecimal.ZERO) >= 0) {
                detail.setSalesPrice(goodsPrice.divide(saleUnit, 4, BigDecimal.ROUND_HALF_DOWN).toString());
            } else {
                throw EC.ERROR.exception("初始化文固so 失败!!! 销售价格不合法 so bill code =" + so.getSoBillCode());
            }
            detail.setExt(soDetail.getExt());
            details.add(detail);
        }

        order.setItems(details);
        return order;
    }

    /**
     * 调拨单请求参数
     *
     * @param costomerId
     * @param ownerId
     * @param ofcSupplier
     * @return
     */
    protected CreateWgStoReqHead getCreateWgStoReq(String costomerId, String ownerId, OfcSupplier ofcSupplier) {

        CreateWgStoReqHead stoReqHead = new CreateWgStoReqHead();

        stoReqHead.setCustomerId(costomerId);
        stoReqHead.setOwnerId(ownerId);
        stoReqHead.setSendWarehouseCode(this.so.getSupplierDc());
        stoReqHead.setReceiveWarehouseCode(ofcSupplier.getSupplierDc());
        stoReqHead.setOrderId(this.so.getSoBillCode());
        stoReqHead.setAddressInfo(this.ofcOrderHead.getAddressInfo());

        List<OfcSoDetail> soDetails = this.so.getDetails();
        List<CreateWgStoReqDetail> details = new ArrayList<>(soDetails.size());
        for (OfcSoDetail soDetail : soDetails) {

            CreateWgStoReqDetail detail = new CreateWgStoReqDetail();
            detail.setLineNo(String.valueOf(soDetail.getItemNo()));
            detail.setGoodsId(soDetail.getSkuSupplyCode());
            //TODO:箱规,默认写1
            detail.setUnit("EA");
            detail.setQty(soDetail.getSkuOrderQty());

            details.add(detail);
        }

        stoReqHead.setItems(details);
        return stoReqHead;
    }

    /**
     * 物美OFC请求参数
     *
     * @return
     */
    protected CreateSoReqHead getCreateSoReq() {
        CreateSoReqHead order = new CreateSoReqHead();
        order.setSoCode(this.so.getSoCode());
        order.setOrderCode(this.so.getSoBillCode());
        order.setWarehouse(this.so.getSupplierDc());
        order.setRegionCode(this.so.getRegionCode());
        order.setSoUserCode(this.customer.getMpCustCode());
        order.setFulfillWms(this.so.getFulfillWms());
        order.setSupplierOrg(this.so.getSupplierOrg());
        order.setSupplierId(this.so.getSupplierId());
        order.setSupplierCode(this.so.getSupplierCode());
        order.setSupplierGroup(this.so.getSupplierGroup());

        JSONObject ext = JSON.parseObject(this.so.getExt());
        Integer lgortType = ext.getInteger(Constants.SO_H_LGORT_TYPE);
        order.setLgortType(lgortType);

        List<OfcSoDetail> items = this.so.getDetails();
        List<CreateSoReqDetail> details = new ArrayList<>(items.size());
        DecimalFormat format = new DecimalFormat("000000");
        for (OfcSoDetail item : items) {
            CreateSoReqDetail detail = new CreateSoReqDetail();
            detail.setItemNum(format.format(item.getItemNo()));
            detail.setSkuCode(item.getSkuSupplyCode());
            detail.setQuality(item.getSkuOrderQty());
            detail.setAmount(item.getGoodsAmount());
            detail.setExt(item.getExt());
            // 商品成本价，即物美售价
//            detail.setGoodsPrice(item.getSkuSupplyPrice());
            details.add(detail);
        }
        order.setDetails(details);
        return order;
    }

    protected MeipiCustomer getMeipiCustomer() {
        MeipiCustomer mpCustomer = new MeipiCustomer();
        mpCustomer.setRegionCode(this.customer.getRegionCode());
        mpCustomer.setMarketName(this.customer.getCustName());
        mpCustomer.setSoUserCode(this.customer.getMpCustCode());
        mpCustomer.setSoUserRegion(this.customer.getMpCustZone());
        mpCustomer.setContactName(this.customer.getContactName());
        mpCustomer.setContactPhone(this.customer.getContactPhone());
        mpCustomer.setProvince(this.customer.getProvince());
        mpCustomer.setCity(this.customer.getCity());
        mpCustomer.setDistrict(this.customer.getDistrict());
        mpCustomer.setAddress(this.customer.getAddress());
        mpCustomer.setSupplyOrg(this.customer.getSupplyOrg());
        mpCustomer.setDc(this.customer.getDc());
        mpCustomer.setSupplierId(this.customer.getSupplierId());
        mpCustomer.setCusType(this.customer.getCusType());
        mpCustomer.setSupplierGroup(this.customer.getSupplierGroup());
        mpCustomer.setSupplierCode(this.customer.getSupplierCode());
        return mpCustomer;
    }
}
